using System;
using System.Collections.Generic;

namespace LoRel {

    // a join clause match set is when the condition under where matches (underlying unique keys may not be 1-1).
    // we should be able to remove this class entirely by making the UnderlyingExclusiveSubset 
    public class JoinClauseMatchSet {
        private readonly List< UnderlyingExclusiveSubset > m_Subsets;
        private readonly HashSet< UniqueKey > m_UniqueKeys;
        private readonly IList< IndexBucket > m_JoinBuckets;
        private readonly CombinedKeySchema m_UniqueKeySchema;

        public event UniqueKeyAddedHandler NotifyUniqueKeyAdded;

        public JoinClauseMatchSet( Key index_value,
                                   CombinedKeySchema unique_key_schema,
                                   IList<IndexBucket> join_buckets ) {

            m_JoinBuckets = join_buckets;
            m_UniqueKeySchema = unique_key_schema;
            m_Subsets = new List< UnderlyingExclusiveSubset >();
            m_UniqueKeys = new HashSet< UniqueKey >();
            BucketTransaction transaction = new BucketTransaction( index_value, join_buckets.Count );
            
            for (int i = 0; i < join_buckets.Count; i++  ) {
                transaction.ReceiveCompleteBucket( i, join_buckets[ i ] );
            }

                for (int i = 0; i < join_buckets.Count; i++) {
                    UnderlyingExclusiveSubset subset
                        = new UnderlyingExclusiveSubset(m_UniqueKeySchema, 
                            i, transaction);
                    m_Subsets.Add( subset );
                }


            for (int i = 0; i < m_Subsets.Count; i++)
            {
                int i1 = i;
                m_JoinBuckets[i].ChangePending += delegate(Key index_key, TableChangeArgs args)
                {
                    HandleBucketChange(i1, args);
                };
            }
        }

        private UniqueKey GetKey( SubsetKey base_key, Key key_part, int key_part_index ) {
            Pair<int> key_bounds;
            m_UniqueKeySchema.GetBounds(key_part_index, out key_bounds);
            IComparable[] items = m_UniqueKeySchema.CreateEmpty();
            base_key.CopyTo(0, items, 0, items.Length);
            key_part.CopyTo(0, items, key_bounds.Left, key_bounds.Right - key_bounds.Left);
            return (new UniqueKey(key_part.CombinedNulls(base_key), items));
        }

        private void HandleBucketChange( int join_part_index, 
                                         TableChangeArgs args)
        {
            foreach( TableChangeItem change_item in args.ChangedItems ) {

                Console.WriteLine("'" + join_part_index + "' Fired " + change_item.NewValue.Key );

                if( args.ChangeType == ChangeType.Add ) {
                    foreach (SubsetKey key in m_Subsets[join_part_index].SubsetKeys)
                    {
                        NotifyUniqueKeyAdded(GetKey(key, change_item.NewValue.Key, join_part_index));
                    }   
                } else {
                    throw new NotImplementedException();
                }
            }
            
        }

        public void NotifyDependantsAddition( UniqueKey addition, IEnumerable<UnderlyingExclusiveSubset> dependant_sets ) {
            foreach( UnderlyingExclusiveSubset subset in dependant_sets ) {
                subset.AddUniqueKey( addition );
            }
        }

        public List<UniqueKey> GetAdditionList( SubsetKey key, UnderlyingExclusiveSubset source_set ){
            List<UniqueKey> unique_keys = new List<UniqueKey>();
            
            foreach (UniqueKey subset_keys in source_set.SubsetKeys)
            {
                unique_keys.Add( subset_keys );
            }
            return unique_keys;
        }
    }
}